#!/usr/bin/python

import os
import time
import datetime
#import hashlib
import sys
import filecmp
import threading
import signal

from os.path import join, getsize

class myMonitor(threading.Thread):
	
	messages = dict()
	
	def __init__(self):
		threading.Thread.__init__(self)
		self.value = -1
		self.running = False
		
	def run(self):
		self.running = True
		while self.running:
			for (message,value) in self.messages.iteritems():
				sys.stdout.write("%s=%i " % (message,value))
			sys.stdout.write("\r")
			sys.stdout.flush()
			time.sleep(2)
	
	def update(self, message, value):
		self.messages[message] = value
		
	def stop(self):
		self.running = False

class findDuplicate(threading.Thread):

	initialPath = ''
	duplicated = 0

	def __init__(self, initialPath):
		threading.Thread.__init__(self)
		self.fileSystemPath = dict()
		self.initialPath = initialPath
		self.running = True
		self.timedelta = datetime.datetime.today() - datetime.datetime.today()
		
	''' Walk over all file tree starting file initialPath '''		
	def run(self):
		self.totalsize=0
		self.filecounter=0
		self.dircounter=0
		self.running = True
		localMonitor = myMonitor()
		localMonitor.update("Duplicated", 0)
		localMonitor.start()
		before = datetime.datetime.today()
		for root, dirs, files in os.walk(self.initialPath):
			if not self.running:
				break
			self.filecounter += len(files)
			localMonitor.update("files", self.filecounter)
			self.dircounter += len(dirs)
			for name in files:
				filepath = join(root,name)
#				print filepath
				if os.path.islink(filepath):
					continue
				size = getsize(filepath)
				if size in self.fileSystemPath:
					s = self.fileSystemPath[size]
					for x in s:
#						print x
						if filecmp.cmp(x,filepath):
							s.add(filepath)
#							print "Duplicated (%i)= %s\n" % (len(s),filepath) 
							self.totalsize += getsize(filepath)
							self.duplicated += 1
							localMonitor.update("Duplicated", self.duplicated)
						break
				else:
					self.fileSystemPath[size] = set([filepath])
		localMonitor.stop()
		localMonitor.join()
		after = datetime.datetime.today()
		self.timedelta = after - before
		
	def results(self):
		for (_k,allPaths) in self.fileSystemPath.iteritems():
			if len(allPaths) >= 2:
				for filePath in allPaths:
					print "Dups: %s" % filePath
				print "====================="
					
		print "self.timedelta = %i:%i:%i" % (self.timedelta.days,self.timedelta.seconds,self.timedelta.microseconds)
		print "Duplicated Size = %iM" % (self.totalsize / (1024 * 1024))
		print "Files = %i" % self.filecounter
		print "Dirs = %i" % self.dircounter
		print "Duplicated = %i" % self.duplicated
		
	def removeInitialPath(self, filepath):
		splitFilePath = filepath.split(os.sep)
		splitInitialPath = self.initialPath.split(os.sep)
		index = len(splitInitialPath)-1
		newPath = ""
		for j in range(index,len(splitFilePath)):
			newPath = os.path.join(newPath,splitFilePath[j])
		return newPath
		
	''' Moving duplicated files to new folder '''
	def moveTo(self, newFolder):
#		if not os.path.exists(newFolder):
#			os.mkdir(newFolder)
		for (_k,allPaths) in self.fileSystemPath.iteritems():
			if len(allPaths) >= 2:
				first = True
				for filePath in allPaths:
					if first:
						first = False
						continue
					newPath = os.path.join(newFolder,self.removeInitialPath(filePath))
					try:
						os.makedirs(os.path.dirname(newPath))
					except OSError:
						None
#					(filepath,_filename) = os.path.split(newPath)
#					newFilePath = os.path.join(newPath,os.path.basename(filePath))
					print "Moving %s to %s" % (filePath,newPath)
					os.rename(filePath,newPath)
				print "Done"
				
	''' Removing only empty folders '''
	def removeEmptyDirs(self):
		for root, dirs, _files in os.walk(self.initialPath):
			for emptydir in dirs:
				try:
					os.rmdir(os.path.join(root,emptydir))
				except OSError:
					None

	def stop(self):
		self.running = False

dup = None
		
def stopAll(signum, frame):
	print 'Signal handler called with signal', signum
	dup.stop()

if len(sys.argv) > 1:
	print sys.argv[1]
else:
	print 'Usage: %s <InitialPath>' % sys.argv[0]
	sys.exit(0)

dup = findDuplicate(sys.argv[1])
dup.start()
signal.signal(signal.SIGTERM,stopAll)
signal.signal(signal.SIGINT,stopAll)
dup.join()
dup.results()
#dup.moveTo(os.path.join(sys.argv[1],"DUPLICATED"))
#dup.removeEmptyDirs()

